package icasue.runninginvoke.config;

import icasue.base.config.filter.ElCondition;
import icasue.reflect.annotations.Nullable;
import icasue.runninginvoke.config.properties.TasksConfigProperties;
import icasue.runninginvoke.task.adapter.TaskAdapterService;
import icasue.runninginvoke.task.redis.DateRedisTaskOperate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/11/27 上午8:18
 * @UpdateDate:
 * @Description:
 */
@EnableConfigurationProperties(value = {
        TasksConfigProperties.class
})
public class PluginRunningInvokeConfiguration implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Autowired
    TasksConfigProperties tasksConfig;

    @Bean
    @ConditionalOnMissingBean(TaskAdapterService.class)
    @ElCondition({
            "#environment.getProperty('task.enable','false').equals('true')",
            "#environment.getProperty('task.reference.redisConnectionFactory') != null",
            "#beanFactory.containsBean(#environment.getProperty('task.reference.redisConnectionFactory'))"
    })
    public TaskAdapterService dateRedisTaskAdapterService() throws InstantiationException, IllegalAccessException {
        // getting JedisConnectionFactory.
        Object redisConnectionFactory = applicationContext.getBean(tasksConfig.reference.redisConnectionFactory);
        // instance data redis operator.
        DateRedisTaskOperate dateRedisTaskOperate =
                new DateRedisTaskOperate(redisConnectionFactory, tasksConfig.redisKeyHome);
        // reference or instance thread pool.
        @Nullable ThreadPoolExecutor taskThreadPool = createOrGet();
        // instance adaptor service.
        TaskAdapterService adapterService = TaskAdapterService
                .build(dateRedisTaskOperate)
                .webPortHadBeenMapping(tasksConfig.webPortHadBeenMapping)
                .taskSecurity(tasksConfig.security)
                .threadPool(taskThreadPool)
                .taskFilesResource(tasksConfig.taskResourcePaths.stream().toArray(String[]::new))
                .taskDeclares(tasksConfig.taskDeclares.stream().toArray(TasksConfigProperties.TaskDeclare[]::new));
        return adapterService;
    }

    @Bean
    @ConditionalOnMissingBean(TaskAdapterService.class)
    @ElCondition({
            "#environment.getProperty('task.enable','false').equals('true')",
            "#environment.getProperty('task.reference.jedisPool') != null",
            "#beanFactory.containsBean(#environment.getProperty('task.reference.jedisPool'))"
    })
    public TaskAdapterService jedisTaskAdapterService() throws InstantiationException, IllegalAccessException {
        // getting JedisPool.
        Object jedisPool = applicationContext.getBean(tasksConfig.reference.jedisPool);
        // instance jedis operator.
        DateRedisTaskOperate jedisTaskOperate =
                new DateRedisTaskOperate(jedisPool, tasksConfig.redisKeyHome);
        // reference or instance thread pool.
        @Nullable ThreadPoolExecutor taskThreadPool = createOrGet();
        // instance adaptor service.
        TaskAdapterService adapterService = TaskAdapterService
                .build(jedisTaskOperate)
                .webPortHadBeenMapping(tasksConfig.webPortHadBeenMapping)
                .taskSecurity(tasksConfig.security)
                .threadPool(taskThreadPool)
                .taskFilesResource(tasksConfig.taskResourcePaths.stream().toArray(String[]::new))
                .taskDeclares(tasksConfig.taskDeclares.stream().toArray(TasksConfigProperties.TaskDeclare[]::new));
        return adapterService;
    }

    private ThreadPoolExecutor createOrGet() throws IllegalAccessException, InstantiationException {
        ThreadPoolExecutor threadPool = null;
        if(tasksConfig.reference.threadPool != null){
            threadPool = applicationContext.getBean(tasksConfig.reference.threadPool, ThreadPoolExecutor.class);
        }else {
            threadPool = new ThreadPoolExecutor(
                    tasksConfig.theadPool.coreSize,
                    tasksConfig.theadPool.maxSize,
                    tasksConfig.theadPool.keepAliveTime,
                    tasksConfig.theadPool.timeUnit,
                    tasksConfig.theadPool.workQueue.newInstance()
            );
        }
        return threadPool;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
